home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Technical Documentation / Sample Code / DTS.Lib & Samples / DTS.Lib / File.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-22  |  25.8 KB  |  927 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:         DTS.Lib
  5. ** File:            file.c
  6. ** Some code from:  Traffic Light 2.0 version, by Keith Rollin & John Harvey
  7. ** Modified by:     Eric Soldan
  8. **
  9. ** Copyright © 1990-1991 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13.  
  14.  
  15. /*****************************************************************************/
  16.  
  17.  
  18.  
  19. #include "DTS.Lib2.h"
  20. #include "DTS.Lib.Common.h"
  21. #include "DTS.Lib.protos.h"
  22.  
  23. #ifndef __ERRORS__
  24. #include <Errors.h>
  25. #endif
  26.  
  27. #ifndef __FILES__
  28. #include <Files.h>
  29. #endif
  30.  
  31. #ifndef __IMAGECOMPRESSION__
  32. #include <ImageCompression.h>
  33. #endif
  34.  
  35. #ifndef __MOVIES__
  36. #include <Movies.h>
  37. #endif
  38.  
  39. #ifndef __PACKAGES__
  40. #include <Packages.h>
  41. #endif
  42.  
  43. #ifndef __RESOURCES__
  44. #include <Resources.h>
  45. #endif
  46.  
  47. #ifndef __STRING__
  48. #include <String.h>
  49. #endif
  50.  
  51. #ifndef __TOOLUTILS__
  52. #include <ToolUtils.h>
  53. #endif
  54.  
  55. #include "Utilities.h"
  56.  
  57.  
  58.  
  59. /*****************************************************************************/
  60.  
  61.  
  62.  
  63. extern OSType        gDocCreator;
  64. extern short        gTypeListLen, gwAppWindow;
  65. extern long            gQTVersion;
  66. extern SFTypeList    gTypeList;
  67.  
  68. static OSErr        Create_OpenFile(FSSpec *file, short *refNum, OSType sftype);
  69.  
  70.  
  71.  
  72. /*****************************************************************************/
  73. /*****************************************************************************/
  74.  
  75.  
  76.  
  77. /* This function does the standard document initialization. */
  78.  
  79. #pragma segment File
  80. OSErr    DefaultInitDocument(FileRecHndl frHndl, short version, short numUndos, short numSaveUndos)
  81. {
  82.     TreeObjHndl    root, undo;
  83.     OSErr        err;
  84.  
  85.     err = noErr;
  86.  
  87.     (*frHndl)->d.doc.fhInfo.version = version;
  88.  
  89.     if (root = NewRootObj(ROOTOBJ, 0)) {        /* Create hierarchical data root. */
  90.         (*frHndl)->d.doc.root = root;            /* Link file to hierarchical data. */
  91.         undo = NewRootObj(UNDOOBJ, 0);            /* Create hierarchical undo root. */
  92.         mDerefRoot(root)->undo    = undo;        /* Save hierarchical undo root. */
  93.         mDerefRoot(root)->frHndl  = frHndl;
  94.         if (undo) {
  95.             (*frHndl)->fileState.defaultDoc = true;
  96.             mDerefUndo(undo)->root   = root;    /* Point undo back at file root. */
  97.             mDerefUndo(undo)->frHndl = frHndl;
  98.             mDerefUndo(undo)->maxNumUndos  = numUndos;
  99.             mDerefUndo(undo)->numSaveUndos = numSaveUndos;
  100.         }
  101.         else {
  102.             DefaultFreeDocument(frHndl);
  103.             err = memFullErr;
  104.         }
  105.     }
  106.     else err = memFullErr;
  107.  
  108.     return(err);
  109. }
  110.  
  111.  
  112.  
  113. /*****************************************************************************/
  114.  
  115.  
  116.  
  117. /* This function disposes of the document.  It checks to see if a file is
  118. ** currently open for the document.  If it is, then the document is closed.
  119. ** Once there is no open file for the document, the memory occupied by the
  120. ** document is released. */
  121.  
  122. #pragma segment File
  123. OSErr    DisposeDocument(FileRecHndl frHndl)
  124. {
  125.     OSErr        err, err2;
  126.     short        refNum;
  127.     WindowPtr    window;
  128.     Movie        movie;
  129.  
  130.     err = noErr;
  131.  
  132.     if (frHndl) {
  133.  
  134.         if ((refNum = (*frHndl)->fileState.refNum) != kInvalRefNum) {        /* If file open... */
  135.  
  136.             if ((*frHndl)->fileState.sfType == MovieFileType)        /* If movie file... */
  137.                 err = CloseMovieFile(refNum);                        /* Close it. */
  138.  
  139.             else                                                    /* If not movie file... */
  140.                 err = FSClose(refNum);                                /* Close it.       */
  141.         }
  142.  
  143.         CloseDocResFile(frHndl);                    /* Close resource fork, if opened. */
  144.  
  145.         window = (*frHndl)->fileState.window;
  146.         err2    = DoFreeDocument(frHndl);            /* Free all application-specific document ram. */
  147.  
  148.         if (movie = (*frHndl)->fileState.movie)
  149.             DisposeMovie(movie);                    /* If we have a movie, dispose it. */
  150.  
  151.         if (window)
  152.             SetWRefCon(window, (long)nil);            /* Mark window as no longer having a document. */
  153.  
  154.         if (!err)
  155.             err = err2;
  156.  
  157.         DisposeHandle((Handle)frHndl);                /* Release memory for the document handle. */
  158.     }
  159.  
  160.     return(err);
  161. }
  162.  
  163.  
  164.  
  165. /*****************************************************************************/
  166.  
  167.  
  168.  
  169. /* This function creates a new document.  A handle is created as the
  170. ** reference to the document.  Header information is placed in this handle.
  171. ** The application-specific data follows this header information.  The
  172. ** handle is returned (or nil upon failure), and typically the handle is
  173. ** then stored in the refCon field of the window.  Note that this is a
  174. ** convention, and is not mandatory.  This allows a document to exist that
  175. ** has no window.  A document with no window is useful when the application
  176. ** is called from the finder in response to a print request.  The document
  177. ** can be loaded and printed without involving a window on the screen. */
  178.  
  179. #pragma segment File
  180. OSErr    NewDocument(FileRecHndl *returnHndl, OSType sftype, Boolean incTitleNum)
  181. {
  182.     long            size;
  183.     FileRecHndl        frHndl;
  184.     FileRecPtr        frPtr;
  185.     Str255            untitled;
  186.     StringPtr        pstr;
  187.     OSErr            err;
  188.     short            i;
  189.     Movie            movie;
  190.     static short    untitledCount;
  191.  
  192.     err  = memFullErr;                /* Assume that we will fail. */
  193.  
  194.     size = InitDocumentSize(sftype);
  195.         /* Call the application and ask it how big the frHndl should be for
  196.         ** this document type.  We can't know, so we'll ask. */
  197.  
  198.     if (frHndl = (FileRecHndl)NewHandleClear(size)) {
  199.         /* Create (or try to) the frHndl, initialized to all 0's */
  200.  
  201.         if (returnHndl)
  202.             *returnHndl = frHndl;
  203.  
  204.         for (i = gTypeListLen; --i;) if (sftype == gTypeList[i]) break;
  205.             /* Walk the typeList to find this file type.  We are interested in
  206.             ** where we find the entry.  The position we find it is used as a
  207.             ** string number into the rDefaultTitles STR# resource.  We get
  208.             ** an individual string from this location.  This allows us to
  209.             ** have different default titles for different document types. */
  210.  
  211.         for (++i; i; i--) {
  212.             GetIndString(untitled, rDefaultTitles, i);
  213.             if (untitled[0]) break;        /* Quit if we succeeded at getting one. */
  214.         }
  215.  
  216.         (*frHndl)->fileState.modNum = GetModNum();
  217.             /* In case GetModNum gets moved to another code segment, set this value
  218.             ** prior to dereferencing frHndl into frPtr. */
  219.  
  220.         frPtr = *frHndl;
  221.         frPtr->fileState.sfType                  = sftype;
  222.         frPtr->fileState.modTick                 = TickCount();
  223.         frPtr->fileState.refNum                  = kInvalRefNum;
  224.         frPtr->fileState.resRefNum               = kInvalRefNum;
  225.         frPtr->fileState.fss.vRefNum             = kInvalVRefNum;
  226.         frPtr->fileState.windowID                = rWindow;
  227.             /* The above sets the fileState constants for the document.  Note
  228.             ** that we use a default 'WIND' ID for the expected window resource.
  229.             ** This can be changed later, if the default isn't good enough. */
  230.  
  231.         frPtr->fileState.getDocWindow            = GetStaggeredWindow;
  232.         frPtr->fileState.calcFrameRgnProc        = CalcFrameRgn;
  233.         frPtr->fileState.contentClickProc        = ContentClick;
  234.         frPtr->fileState.contentKeyProc          = ContentKey;
  235.         frPtr->fileState.drawFrameProc           = DrawFrame;
  236.         frPtr->fileState.freeDocumentProc        = FreeDocument;
  237.         frPtr->fileState.freeWindowProc          = FreeWindow;
  238.         frPtr->fileState.imageProc               = ImageDocument;
  239.         frPtr->fileState.initContentProc         = InitContent;
  240.         frPtr->fileState.readDocumentProc        = ReadDocument;
  241.         frPtr->fileState.readDocumentHeaderProc  = DefaultReadDocumentHeader;
  242.         frPtr->fileState.resizeContentProc       = ResizeContent;
  243.         frPtr->fileState.scrollFrameProc         = ScrollFrame;
  244.         frPtr->fileState.undoFixupProc           = UndoFixup;
  245.         frPtr->fileState.windowCursorProc        = WindowCursor;
  246.         frPtr->fileState.writeDocumentProc       = WriteDocument;
  247.         frPtr->fileState.writeDocumentHeaderProc = DefaultWriteDocumentHeader;
  248.             /* Initialize all of the procedure pointers to default values.
  249.             ** If the defaults aren't any good, they will be changed later. */
  250.  
  251.         frPtr->fileState.attributes = gwAppWindow;
  252.             /* Set window attributes for the main document type. If the document
  253.             ** is not the main type, then the application's InitDocument function
  254.             ** will have to change it. */
  255.  
  256.         pstr = frPtr->fileState.fss.name;
  257.         pcpy(pstr, untitled);
  258.         if (incTitleNum)
  259.             ++untitledCount;
  260.         pcatdec(pstr, untitledCount);
  261.             /* Create the default document title.  It is stored in the FSSpec,
  262.             ** as we can't place it in the window title.  We don't have a window
  263.             ** yet to "title".  This will happen later.  The title is gotten from
  264.             ** the FSSpec, so we are effectively done. */
  265.  
  266.         err = InitDocument(frHndl);
  267.             /* Call the application for any additional document initialization.
  268.             ** Other handles may need to be allocated.  The default values above
  269.             ** may be incorrect for a certain document type.  This gives the
  270.             ** application a chance to change any defaults that are incorrect. */
  271.  
  272.         if ((*frHndl)->fileState.sfType == MovieFileType) {
  273.             movie = NewMovie(newMovieActive);
  274.             err   = GetMoviesError();
  275.             if (!err) {
  276.                 ClearMovieChanged(movie);
  277.                 (*frHndl)->fileState.movie = movie;
  278.             }
  279.         }
  280.  
  281.         if (err) {
  282.             DisposeHandle((Handle)frHndl);
  283.             if (returnHndl)
  284.                 *returnHndl = nil;
  285.                     /* If the application couldn't complete the document
  286.                     ** initialization, pitch the handle. */
  287.         }
  288.     }
  289.  
  290.     return(err);
  291. }
  292.  
  293.  
  294.  
  295. /*****************************************************************************/
  296.  
  297.  
  298.  
  299. #pragma segment File
  300. OSErr    OpenDocument(FileRecHndl *result, FSSpecPtr fileToOpen, char permission)
  301. {
  302.     StandardFileReply    reply;
  303.     short                refNum;
  304.     FileRecHndl            frHndl;
  305.     OSErr                err;
  306.     FSSpec                myFileSpec;
  307.     DialogPtr            openDialog;
  308.     short                item;
  309.     FInfo                finderInfo;
  310.     Boolean                openMovie;
  311.     Movie                movie;
  312.     static SFTypeList    typeList = {MovieFileType};
  313.  
  314.     *result = nil;        /* Assume we will fail. */
  315.  
  316.     openMovie = false;
  317.     if (fileToOpen == kOpenMovie) {
  318.         if (!gQTVersion) return(paramErr);        /* Can't do movies without QuickTime. */
  319.         fileToOpen = nil;
  320.         openMovie  = true;
  321.     }
  322.  
  323.     if (!fileToOpen) {
  324.         if (openMovie) {
  325.             StandardGetFilePreview(0L, 1, typeList, &reply);
  326.             if (reply.sfGood)
  327.                 myFileSpec = reply.sfFile;
  328.             else
  329.                 return(userCanceledErr);    /* User canceled. */
  330.         }
  331.         else {
  332.             if (DisplayGetFile(&reply, gTypeListLen, gTypeList))    /* Let user pick file. */
  333.                 myFileSpec = reply.sfFile;                            /* User's choice.       */
  334.             else
  335.                 return(userCanceledErr);    /* User canceled. */
  336.         }
  337.     }
  338.     else {
  339.         err = HGetFInfo(fileToOpen->vRefNum, fileToOpen->parID, fileToOpen->name, &finderInfo);
  340.         if (err) return(err);
  341.         reply.sfType = finderInfo.fdType;        /* OSType of file. */
  342.         myFileSpec   = *fileToOpen;                /* Pre-designated file to open. */
  343.     }
  344.  
  345.     err = NewDocument(&frHndl, reply.sfType, false);
  346.     if (err) return(err);
  347.         /* We couldn't create an empty document, so give it up. */
  348.  
  349.     err = HOpenDF(myFileSpec.vRefNum, myFileSpec.parID, myFileSpec.name, permission, &refNum);
  350.     if (err == paramErr)
  351.         err = HOpen(myFileSpec.vRefNum, myFileSpec.parID, myFileSpec.name, permission, &refNum);
  352.  
  353.     if (err == opWrErr) {
  354.  
  355.         ParamText(myFileSpec.name, nil, nil, nil);
  356.         openDialog = GetCenteredDialog(rOpenReadOnly, nil, nil, (WindowPtr)-1L);
  357.         if (!openDialog) {
  358.             DisposeDocument(frHndl);
  359.             return(err);
  360.         }
  361.  
  362.         OutlineDialogItem(openDialog, kOpenYes);
  363.         DoSetCursor(&qd.arrow);
  364.         UnhiliteWindows();
  365.         ModalDialog((ModalFilterProcPtr)KeyEquivFilter, &item);
  366.         DisposeDialog(openDialog);
  367.         HiliteWindows();
  368.         if (item != kOpenYes) {
  369.             DisposeDocument(frHndl);
  370.             return(userCanceledErr);
  371.         }
  372.  
  373.         (*frHndl)->fileState.readOnly = true;
  374.         permission = fsRdPerm;
  375.         err = HOpenDF(myFileSpec.vRefNum, myFileSpec.parID, myFileSpec.name, permission, &refNum);
  376.         if (err == paramErr)
  377.             err = HOpen(myFileSpec.vRefNum, myFileSpec.parID, myFileSpec.name, permission, &refNum);
  378.     }
  379.  
  380.     if (err) {
  381.         DisposeDocument(frHndl);
  382.         return(err);
  383.     }
  384.  
  385.     if ((*frHndl)->fileState.sfType == MovieFileType) {
  386.         FSClose(refNum);                            /* Close file, as it wasn't opened as movie. */
  387.         if (movie = (*frHndl)->fileState.movie) {
  388.             DisposeMovie(movie);                    /* NewDocument created an empty movie, */
  389.             (*frHndl)->fileState.movie = nil;        /* so first get rid of it. */
  390.         }
  391.         err = OpenMovieFile(&myFileSpec, &refNum, permission);
  392.         if (err) {
  393.             DisposeDocument(frHndl);
  394.             return(err);
  395.         }
  396.     }
  397.  
  398.     (*frHndl)->fileState.fss    = myFileSpec;
  399.     (*frHndl)->fileState.refNum = refNum;
  400.  
  401.     if (err = DoReadDocument(frHndl)) {
  402.         DisposeDocument(frHndl);
  403.         return(err);
  404.     }
  405.  
  406.     *result = frHndl;
  407.     return(noErr);
  408. }
  409.  
  410.  
  411.  
  412. /*****************************************************************************/
  413.  
  414.  
  415.  
  416. #pragma segment File
  417. OSErr    SaveDocument(FileRecHndl frHndl, WindowPtr window, short saveMode)
  418. {
  419.     Str255                closeOrQuit;
  420.     short                item, refNum, resID;
  421.     long                createFlags;
  422.     StandardFileReply    reply;
  423.     OSErr                err;
  424.     Movie                movie;
  425.     Boolean                doPrompt;
  426.     DialogPtr            saveDialog;
  427.  
  428. /*    When entering, saveMode is set to the menu command number of the
  429. **    the item that prompted this. Current settings are kSave, kSaveAs,
  430. **    kClose, and kQuit. */
  431.  
  432.     if (saveMode != kSaveAs) {                        /* If not save as... */
  433.         if (!(*frHndl)->fileState.docDirty) {        /* If file clean...  */
  434.             if (!(*frHndl)->fileState.readOnly)
  435.                 DoWriteDocumentHeader(frHndl);
  436.                     /* Write out document location and print record information. */
  437.             return(noErr);                            /* Consider it saved. */
  438.         }
  439.     }
  440.  
  441.     pcpy(reply.sfFile.name, (*frHndl)->fileState.fss.name);
  442.  
  443.     if ((saveMode == kClose) || (saveMode == kQuit)) {
  444.         /* If implicit save... */
  445.  
  446.         GetIndString(closeOrQuit, rFileIOStrings,
  447.                      (saveMode == kClose) ? sWClosing : sQuitting);
  448.         ParamText(reply.sfFile.name, closeOrQuit, nil, nil);
  449.  
  450.         saveDialog = GetCenteredDialog(rYesNoCancel, nil, window, (WindowPtr)-1L);
  451.  
  452.         if (saveDialog) {
  453.             OutlineDialogItem(saveDialog, kSaveYes);
  454.             DoSetCursor(&qd.arrow);
  455.             UnhiliteWindows();
  456.             ModalDialog((ModalFilterProcPtr)KeyEquivFilter, &item);
  457.             DisposeDialog(saveDialog);
  458.             HiliteWindows();
  459.         }
  460.         else
  461.             item = kSaveNo;
  462.                 /* If the dialog isn't displayed, then AppleScript doesn't want it to.
  463.                 ** In this case, we were probably AppleScripted the whole time, so
  464.                 ** the document is an AppleScript-produced document.  The script is
  465.                 ** done with the document, so ditch the document. */
  466.  
  467.         if (item != kSaveYes) {
  468.             err = noErr;
  469.             if (item == kSaveCanceled)
  470.                 err = userCanceledErr;
  471.             return(err);
  472.         }
  473.     }
  474.  
  475.     doPrompt = (
  476.         (saveMode == kSaveAs) ||
  477.         ((*frHndl)->fileState.refNum == kInvalRefNum)
  478.     );
  479.  
  480.     if (doPrompt) {
  481.         /* Prompt with SFGetFile if doing a Save As or have never saved before. */
  482.  
  483.         if (!DisplayPutFile(&reply)) return(userCanceledErr);    /* User canceled the save. */
  484.  
  485.         if ((*frHndl)->fileState.sfType != MovieFileType) {
  486.             if ((*frHndl)->fileState.refNum != kInvalRefNum) {
  487.                 if ((*frHndl)->fileState.sfType != MovieFileType) {
  488.                     CloseDocResFile(frHndl);        /* Close resource fork, if opened. */
  489.                     FSClose((*frHndl)->fileState.refNum);
  490.                 }
  491.             }            /* Close the old file.  Don't respond to any error here because
  492.                         ** the user may be trying to do a save-as because their old file
  493.                         ** is bad.  If we fail to close the old file, and then respond
  494.                         ** to the error, the user won't get the opportunity to save
  495.                         ** their document to a new file. */
  496.  
  497.             (*frHndl)->fileState.refNum      = kInvalRefNum;
  498.             (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  499.             if (err = Create_OpenFile(&reply.sfFile, &refNum, (*frHndl)->fileState.sfType))
  500.                 return(err);
  501.         }
  502.         else {
  503.             createFlags = createMovieFileDeleteCurFile;
  504.             err = CreateMovieFile(&reply.sfFile, gDocCreator, 0, createFlags, &refNum, nil);
  505.             if (err) return(err);
  506.             resID = 0;
  507.             err = AddMovieResource((*frHndl)->fileState.movie, refNum, &resID, nil);
  508.             if (err) return(err);
  509.             (*frHndl)->fileState.movieResID = resID;
  510.         }
  511.  
  512.         (*frHndl)->fileState.fss    = reply.sfFile;        /* This is the new file. */
  513.         (*frHndl)->fileState.refNum = refNum;
  514.  
  515.         if (window)
  516.             NewWindowTitle(window, nil);
  517.     }
  518.     else {
  519.         if ((*frHndl)->fileState.sfType == MovieFileType) {
  520.             movie  = (*frHndl)->fileState.movie;
  521.             refNum = (*frHndl)->fileState.refNum;
  522.             resID  = (*frHndl)->fileState.movieResID;
  523.             err = UpdateMovieResource(movie, refNum, resID, nil);
  524.             if (err) return(err);
  525.         }
  526.     }
  527.  
  528.     if (err = DoWriteDocument(frHndl)) return(err);
  529.  
  530.     (*frHndl)->fileState.docDirty = false;
  531.     (*frHndl)->fileState.readOnly = false;
  532.     return(noErr);
  533. }
  534.  
  535.  
  536.  
  537. /*****************************************************************************/
  538.  
  539.  
  540.  
  541. /* ConvertOldToNewSFReply
  542. **
  543. ** struct StandardFileReply {            struct SFReply {
  544. **     Boolean     sfGood;                <-    Boolean good;
  545. **     Boolean     sfReplacing;        <-    Boolean copy;
  546. **     OSType         sfType;                <-    OSType fType;
  547. **     FSSpec        sfFile;
  548. **                     vRefNum;        <-    real vRefnum from (short vRefNum)
  549. **                     parID;            <-    real dirID from (short vRefNum)
  550. **                     name;            <-    Str63 fName;
  551. **     ScriptCode    sfScript;            <-    iuSystemScript
  552. **     short         sfFlags;            <-    0
  553. **     Boolean     sfIsFolder;            <-    false
  554. **     Boolean     sfIsVolume;            <-    false
  555. **     long        sfReserved1;        <-    0
  556. **     short        sfReserved2;        <-    0
  557. ** };                                    };
  558. */
  559.  
  560. #pragma segment File
  561. void    ConvertOldToNewSFReply(SFReply *oldReply, StandardFileReply *newReply)
  562. {
  563.     OSErr        err;
  564.     long        ignoredProcID;
  565.     
  566.     newReply->sfGood        = oldReply->good;
  567.     newReply->sfReplacing    = oldReply->copy;        /* Correct assignment? */
  568.     newReply->sfType        = oldReply->fType;
  569.  
  570.     err = GetWDInfo(oldReply->vRefNum,
  571.                     &newReply->sfFile.vRefNum,
  572.                     &newReply->sfFile.parID,
  573.                     &ignoredProcID);
  574.     pcpy(newReply->sfFile.name, oldReply->fName);
  575.  
  576.     /* Punt on the rest... */
  577.     newReply->sfScript        = iuSystemScript;
  578.     newReply->sfFlags        = 0;
  579.     newReply->sfIsFolder    = false;
  580.     newReply->sfIsVolume    = false;
  581.     newReply->sfReserved1    = 0;
  582.     newReply->sfReserved2    = 0;
  583. }
  584.  
  585.  
  586.  
  587. /*****************************************************************************/
  588.  
  589.  
  590.  
  591. /* Opens the file specified by the passed FSSpec, creating it if it doesn't
  592. ** already exist. Returns the refnum of the open file to the application.
  593. ** File Manager errors are reported and returned. */
  594.  
  595. #pragma segment File
  596. OSErr    Create_OpenFile(FSSpec *file, short *refNum, OSType sftype)
  597. {
  598.     OSErr    err;
  599.  
  600.     err = HCreate(file->vRefNum, file->parID, file->name, gDocCreator, sftype);
  601.     if (err == dupFNErr) {
  602.  
  603.         /* The user already told Standard File to replace the old file
  604.            so let's get rid of it. */
  605.  
  606.         HDelete(file->vRefNum, file->parID, file->name);
  607.  
  608.         /* Try creating it again. */
  609.         err = HCreate(file->vRefNum, file->parID, file->name, gDocCreator, sftype);
  610.     }
  611.  
  612.     if (!err) {
  613.         err = HOpenDF(file->vRefNum, file->parID, file->name, fsRdWrPerm, refNum);
  614.         if (err == paramErr)
  615.             err = HOpen(file->vRefNum, file->parID, file->name, fsRdWrPerm, refNum);
  616.         if (err)
  617.             HDelete(file->vRefNum, file->parID, file->name);
  618.     }
  619.  
  620.     return(err);
  621. }
  622.  
  623.  
  624.  
  625. /*****************************************************************************/
  626.  
  627.  
  628.  
  629. /* Simple routine to display a list of files with our file type. */
  630.  
  631. #pragma segment File
  632. Boolean    DisplayGetFile(StandardFileReply *reply, short typeListLen, SFTypeList typeList)
  633. {
  634.     Point        where = {100, 100};
  635.     SFReply        oldReply;
  636.  
  637.     if (gSystemVersion >= 0x0700)        /* If new standard file available... */
  638.         StandardGetFile(nil, typeListLen, typeList, reply);
  639.  
  640.     else {
  641.         SFGetFile(where, "\pSelect a document to open.",
  642.                          nil, typeListLen, typeList, nil, &oldReply);
  643.         ConvertOldToNewSFReply(&oldReply, reply);
  644.     }
  645.  
  646.     return(reply->sfGood);
  647. }
  648.  
  649.  
  650.  
  651. /*****************************************************************************/
  652.  
  653.  
  654.  
  655. /* Displays the StandardFile PutFile dialog box. Fills out the passed reply
  656. ** record, and returns the sfGood field as a result. */
  657.  
  658. #pragma segment File
  659. Boolean    DisplayPutFile(StandardFileReply *reply)
  660. {
  661.     Str255        prompt;
  662.     Point        where = {100, 100};
  663.     SFReply        oldReply;
  664.  
  665.     GetIndString(prompt, rFileIOStrings, sSFprompt);
  666.  
  667.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  668.         StandardPutFile(prompt, reply->sfFile.name, reply);
  669.     else {
  670.         SFPutFile(where, prompt, reply->sfFile.name, nil, &oldReply);
  671.         ConvertOldToNewSFReply(&oldReply, reply);
  672.     }
  673.  
  674.     return(reply->sfGood);
  675. }
  676.  
  677.  
  678.  
  679. /*****************************************************************************/
  680.  
  681.  
  682.  
  683. /* Use the resource fork for the designated document file.  This function
  684. ** also returns the old CurResFile, so you can set it back when you are done.
  685. ** Simply call this function, whether or not you have a resource fork.  If
  686. ** there isn't a resource fork, then one will be created.  If there is one,
  687. ** but it isn't open yet, it will be opened.  If it is already opened, it
  688. ** sets it as the current resource fork.  What more do you want? */
  689.  
  690. #define fcbFlgRBit 0x200
  691.  
  692. #pragma segment File
  693. OSErr    UseDocResFile(FileRecHndl frHndl, short *oldRes, char perm)
  694. {
  695.     OSErr        err;
  696.     FSSpec        fss;
  697.     short        res, vrn;
  698.     long        pid;
  699.     FCBPBRec    pb;
  700.  
  701.     if (oldRes)
  702.         *oldRes = CurResFile();
  703.  
  704.     if ((res = (*frHndl)->fileState.resRefNum) != kInvalRefNum) {
  705.         UseResFile(res);        /* If the resource fork already open, use it. */
  706.         return(ResError());
  707.     }
  708.  
  709.     memset(&pb, 0, sizeof(FCBPBRec));        /* Make most of the param block happy. */
  710.     pb.ioRefNum = res = (*frHndl)->fileState.refNum;
  711.     if (err = PBGetFCBInfoSync(&pb)) return(err);
  712.     if (pb.ioFCBFlags & fcbFlgRBit) {
  713.         (*frHndl)->fileState.resRefNum = res;
  714.         UseResFile(res);
  715.         return(ResError());
  716.     }
  717.  
  718.     fss = (*frHndl)->fileState.fss;
  719.     vrn = fss.vRefNum;
  720.     pid = fss.parID;
  721.  
  722.     res = HOpenResFile(vrn, pid, fss.name, perm);
  723.         /* Try opening the resource fork. */
  724.  
  725.     if (err = ResError()) {
  726.         if (err != eofErr) return(err);                    /* Some errors we can't handle here. */
  727.         HCreateResFile(vrn, pid, fss.name);                /* No resource fork, so create one.  */
  728.         if (err = ResError()) return(err);                /* Error creating the resource fork. */
  729.         res = HOpenResFile(vrn, pid, fss.name, perm);    /* Now that it exists, open it.  */
  730.         err = ResError();                                /* Return whatever error occurs. */
  731.     }
  732.  
  733.     if (!err) {        /* If no error, then we can use the resource fork. */
  734.         (*frHndl)->fileState.resRefNum = res;
  735.         UseResFile(res);
  736.         err = ResError();
  737.     }
  738.  
  739.     return(err);
  740. }
  741.  
  742.  
  743.  
  744. /*****************************************************************************/
  745.  
  746.  
  747.  
  748. /* If there is a resource fork open for this document, this closes it. */
  749.  
  750. #pragma segment File
  751. OSErr    CloseDocResFile(FileRecHndl frHndl)
  752. {
  753.     short    res;
  754.  
  755.     if ((res = (*frHndl)->fileState.resRefNum) == kInvalRefNum) return(noErr);
  756.         /* If it was never opened, then there's nothing to close. */
  757.  
  758.     if ((*frHndl)->fileState.refNum == res) {
  759.         (*frHndl)->fileState.resRefNum = kInvalRefNum;
  760.         return(noErr);
  761.     }
  762.  
  763.     CloseResFile(res);                                    /* Close the resource fork. */
  764.     (*frHndl)->fileState.resRefNum = kInvalRefNum;        /* Mark it as closed. */
  765.  
  766.     return(ResError());
  767. }
  768.  
  769.  
  770.  
  771. /*****************************************************************************/
  772.  
  773.  
  774.  
  775. #pragma segment File
  776. long    GetModNum(void)
  777. {
  778.     static    modNum = 0;
  779.  
  780.     return(++modNum);
  781. }
  782.  
  783.  
  784.  
  785. /*****************************************************************************/
  786.  
  787.  
  788.  
  789. /* This function returns the state of the document.  If the document
  790. ** is dirty, then true is returned.  If the document is clean, then false
  791. ** is returned. */
  792.  
  793. #pragma segment File
  794. Boolean    GetDocDirty(FileRecHndl frHndl)
  795. {
  796.     if (frHndl) return((*frHndl)->fileState.docDirty);
  797.     return(false);
  798. }
  799.  
  800.  
  801.  
  802. /*****************************************************************************/
  803.  
  804.  
  805.  
  806. /* This function returns the state of the window's document.  If the document
  807. ** is dirty, then true is returned.  If the document is clean, or the window
  808. ** has no document, then false is returned. */
  809.  
  810. #pragma segment File
  811. Boolean    GetWindowDirty(WindowPtr window)
  812. {
  813.     if (IsAppWindow(window)) return(GetDocDirty((FileRecHndl)GetWRefCon(window)));
  814.     return(false);
  815. }
  816.  
  817.  
  818.  
  819. /*****************************************************************************/
  820.  
  821.  
  822.  
  823. #pragma segment File
  824. void    SetDocDirty(FileRecHndl frHndl)
  825. {
  826.     if (frHndl) {
  827.         (*frHndl)->fileState.docDirty = true;
  828.         (*frHndl)->fileState.modNum   = GetModNum();
  829.         (*frHndl)->fileState.modTick  = TickCount();
  830.     }
  831. }
  832.  
  833.  
  834.  
  835. /*****************************************************************************/
  836.  
  837.  
  838.  
  839. #pragma segment File
  840. void    SetWindowDirty(WindowPtr window)
  841. {
  842.     if (IsAppWindow(window))
  843.         SetDocDirty((FileRecHndl)GetWRefCon(window));
  844. }
  845.  
  846.  
  847.  
  848. /*****************************************************************************/
  849.  
  850.  
  851.  
  852. #pragma segment File
  853. /*  The SetDefault function sets the default volume and directory to the volume specified
  854. **  by newVRefNum and the directory specified by newDirID. The current default volume 
  855. **  and directory are returned in oldVRefNum and oldDir and should be used to restore 
  856. **  things to their previous condition *as soon as possible* with the RestoreDefault 
  857. **  function. These two functions are designed to be used as a wrapper around
  858. **  Standard C I/O routines where the location of the file is implied to be the
  859. **  default volume and directory. In other words, this is how you should use these
  860. **  functions:
  861. **
  862. **        err = SetDefault(newVRefNum, newDirID, &oldVRefNum, &oldDirID);
  863. **        if (!err)
  864. **            {
  865. **                // call the Stdio functions like remove, rename, tmpfile, fopen, 
  866. **                // freopen, etc. or non-ANSI extentions like fdopen, fsetfileinfo,
  867. **                // create, open, unlink, etc. here!
  868. **
  869. **                err = RestoreDefault(oldVRefNum, oldDirID);
  870. **            }
  871. **
  872. **  By using these functions as a wrapper, you won't need to open a working directory 
  873. **  (because they use HSetVol) and you won't have to worry about the effects of using
  874. **  HSetVol (documented in Technical Note #140: Why PBHSetVol is Dangerous 
  875. **  and in the Inside Macintosh: Files book in the description of the HSetVol and 
  876. **  PBHSetVol functions) because the default volume/directory is restored before 
  877. **  giving up control to code that might be affected by HSetVol.
  878. ** Use this and the below call instead of the old-style FSpSetWD and FSpResetWD. */
  879.  
  880. OSErr    SetDefault(short newVRefNum, long newDirID, short *oldVRefNum, long *oldDirID)
  881. {
  882.     OSErr    err;
  883.  
  884.     err = HGetVol(nil, oldVRefNum, oldDirID);
  885.         /* Get the current default volume/directory. */
  886.  
  887.     if (!err)
  888.         err = HSetVol(nil, newVRefNum, newDirID);
  889.             /* Set the new default volume/directory */
  890.  
  891.     return(err);
  892. }
  893.  
  894.  
  895.  
  896. /*****************************************************************************/
  897.  
  898.  
  899.  
  900. #pragma segment File
  901. OSErr    RestoreDefault(short oldVRefNum, long oldDirID)
  902. {
  903.     OSErr    err;
  904.     short    defaultVRefNum;
  905.     long    defaultDirID;
  906.     long    defaultProcID;
  907.  
  908.     err = GetWDInfo(oldVRefNum, &defaultVRefNum, &defaultDirID, &defaultProcID);
  909.         /* Determine if the default volume was a wdRefNum. */
  910.  
  911.     if (!err) {
  912.         /* Restore the old default volume/directory, one way or the other. */
  913.  
  914.         if (defaultDirID != fsRtDirID)
  915.             err = SetVol(nil, oldVRefNum);
  916.                 /* oldVRefNum was a wdRefNum - use SetVol */
  917.         else
  918.             err = HSetVol(nil, oldVRefNum, oldDirID);
  919.                 /* oldVRefNum was a real vRefNum - use HSetVol */
  920.     }
  921.  
  922.     return(err);
  923. }
  924.  
  925.  
  926.  
  927.